#include "../include/hash.h"
#include <stdio.h>
#include <stdlib.h>

typedef struct node_s {
	int a;
	hash_t hash;
}node_t;

#define N 20

void pw(char * msg) {
	printf("wrong:%s\n", msg);
}
void pr(char * msg) {
	printf("right:%s\n", msg);
}

void check_hash_set_space() {
	hash_head_t head;
	init_head(hash_head_t, &head);
	char * p = (char *) malloc( sizeof(hash_t *) * N);		
	hash_set_space(&head, p, sizeof(hash_t *) * N);	

	if (head.op != HASH_OP_DEF) {
		pw("hash_set_space");
		return ;	
	}
	if (head.n != N) {
		pw("hash_set_space");
		return ;	
	}
	if ((char *)head.phash != p) {
		pw("hash_set_space");
		return ;
	}
	pr("hash_set_space");
}

void check_hash_set_function() {
	hash_head_t head;
        init_head(hash_head_t, &head);
        char * p = (char *) malloc( sizeof(hash_t *) * N);
        hash_set_space(&head, p, sizeof(hash_t *) * N);
		
	hash_set_function(&head, HASH_OP_NULL);
	if (head.op != HASH_OP_NULL) {
		pw("hash_set_function");
		return;
	} 
	pr("hash_set_function");
}

void check_hash_is_empty() {
	hash_head_t head;
        init_head(hash_head_t, &head);

	if (!hash_is_empty(&head)) {
		pw("hash_is_empty");
		return;	
	}
        char * p = (char *) malloc( sizeof(hash_t *) * N);
        hash_set_space(&head, p, sizeof(hash_t *) * N);
	if (hash_is_empty(&head)) {
		pw("hash_is_empty");
		return;
	}
	pr("hash_is_empty");
}

void check_hash_empty() {
	hash_head_t head;	
	init_head(hash_head_t, &head);
	char * p = (char *) malloc( sizeof(hash_t *) * N);
        hash_set_space(&head, p, sizeof(hash_t *) * N);

	hash_empty(&head);
	if (!hash_is_empty(&head)) {
		pw("hash_empty");
	}
	pr("hash_empty");
}

void check_hash_set_key() {
	hash_t unit;
	hash_set_key(&unit, 10);
	if (unit.key != 10) {
		pw("hash_set_key");
		return;
	}					
	pr("hash_set_key");
}

void check_hash_get_key() {
	hash_t unit;
	unit.key = 10;
	if (10 != hash_get_key(&unit)) {
		pw("hash_get_key");
		return;
	}
	pr("hash_get_key");
}

void check_hash_add() {
	hash_head_t head;
	hash_t * punit;
	node_t nodes[N];
	node_t nodes1[N];	
	node_t *pnode;
	int i = 0;

        init_head(hash_head_t, &head);
        char * p = (char *) malloc( sizeof(hash_t *) * N);
        hash_set_space(&head, p, sizeof(hash_t *) * N);	

	for (i = 0; i < N; i++) {
		nodes[i].a = i+1;
		nodes1[i].a = i+1;
		hash_set_key(&(nodes[i].hash), i);
		hash_set_key(&(nodes1[i].hash), i);
	}	
	
	for (i = 0; i < N; ++i) {
		hash_add(&head, &(nodes[i].hash));
	}
	for (i = 0; i < N; ++i) {
		punit = *(head.phash+i);	
		if (punit == NULL) {
			continue;
		} 
		pnode = entry(punit, node_t, hash);
		if (pnode->a != i+1) {
			pw("hash_add");
			return ;
		}	
	}

	for (i = 0; i < N; ++i) {
		hash_add(&head, &(nodes1[i].hash));
	}
	for (i = 0; i < N; ++i) {
                punit = *(head.phash+i);
		punit = punit->next;
		
                pnode = entry(punit, node_t, hash);
                if (pnode->a != i+1) {
                        pw("hash_add");
                        return ;
                }
		if (punit->next != NULL) {
			pw("hash_add");
			return;
		}
        }
	pr("hash_add");
	
}

void check_hash_del() {
	hash_head_t head;
        hash_t * punit;
        node_t nodes[N];
        node_t *pnode;
        int i = 0;

        init_head(hash_head_t, &head);
        char * p = (char *) malloc( sizeof(hash_t *) * N);
        hash_set_space(&head, p, sizeof(hash_t *) * N);

        for (i = 0; i < N; i++) {
                nodes[i].a = i+1;
                hash_set_key(&(nodes[i].hash), i);
        }
        for (i = 0; i < N; ++i) {
                hash_add(&head, &(nodes[i].hash));
        }	
	
	hash_del(&head, &(nodes[9].hash));

	for (i = 0; i < N; ++i) {
		punit = *(head.phash+i);	
		if (punit == NULL) {
			continue;
		} 
		pnode = entry(punit, node_t, hash);
		if (pnode->a == 10) {
			pw("hash_del");
			return ;
		}	
	}
	pr("hash_del");
}

void check_hash_del_by_key() {
	hash_head_t head;
        hash_t * punit;
        node_t nodes[N];
        node_t *pnode;
        int i = 0;

        init_head(hash_head_t, &head);
        char * p = (char *) malloc( sizeof(hash_t *) * N);
        hash_set_space(&head, p, sizeof(hash_t *) * N);

        for (i = 0; i < N; i++) {
                nodes[i].a = i+1;
                hash_set_key(&(nodes[i].hash), i);
        }
        for (i = 0; i < N; ++i) {
                hash_add(&head, &(nodes[i].hash));
		hash_add(&head, &(nodes[i].hash));
        }      

	
        hash_del_by_key(&head, hash_get_key(&(nodes[9].hash)));

        for (i = 0; i < N; ++i) {
                punit = *(head.phash+i);
		if (i == 9) {
                	if (punit != NULL) {
				pw("hash_del_by_key");	
				return;
                	}
		}
               	if (punit == NULL) {
                        continue;
               	}
                pnode = entry(punit, node_t, hash);
                if (pnode->a == 10) {
                        pw("hash_del_by_key");
                        return ;
                }
        }
        pr("hash_del_by_key");
}

void check_hash_find_count() {
	hash_head_t head;
        hash_t * punit;
        node_t nodes[N];
	node_t nodes1[N];
        node_t *pnode;
        int i = 0;

        init_head(hash_head_t, &head);
        char * p = (char *) malloc( sizeof(hash_t *) * N);
        hash_set_space(&head, p, sizeof(hash_t *) * N);

        for (i = 0; i < N; i++) {
                nodes[i].a = i+1;
		nodes1[i].a = i+1;
                hash_set_key(&(nodes[i].hash), i);
                hash_set_key(&(nodes1[i].hash), i);
        }
        for (i = 0; i < N; ++i) {
                hash_add(&head, &(nodes[i].hash));
                hash_add(&head, &(nodes[i].hash));
        }
	
	for (i = 0; i < N; i++) {
		if (hash_find_count(&head, i) != 1) {
			pw("hash_find_count");
			return ;
		}	
	}
	for (i = 0; i < N; ++i) {
		hash_add(&head, &(nodes1[i].hash));
	}
	for (i = 0; i < N; i++) {
		if (hash_find_count(&head, i) != 2) {
			pw("hash_find_count");
			return ;
		}	
	}
	pr("hash_find_count");
}

void check_hash_find() {
	hash_head_t head;
        hash_t * punit;
        node_t nodes[N];
        node_t nodes1[N];
        node_t *pnode;
        int i = 0;

        init_head(hash_head_t, &head);
        char * p = (char *) malloc( sizeof(hash_t *) * N);
        hash_set_space(&head, p, sizeof(hash_t *) * N);

        for (i = 0; i < N; i++) {
                nodes[i].a = i+1;
                nodes1[i].a = i+1;
                hash_set_key(&(nodes[i].hash), i);
                hash_set_key(&(nodes1[i].hash), i);
        }
        for (i = 0; i < N; ++i) {
                hash_add(&head, &(nodes[i].hash));
                hash_add(&head, &(nodes1[i].hash));
        }
	
	punit = (hash_t *)hash_find(&head, 5, 1);
	if (punit != &(nodes[5].hash)) {
		pw("hash_find");
		return ;
	}	
	pnode = entry(punit, node_t, hash);
	if (pnode->a != 6) {
		pw("hash_find");
		return;
	}
	punit = (hash_t *)hash_find(&head, 5, 0);
	if (punit != &(nodes1[5].hash)) {
                pw("hash_find");
                return ;
        }       
        pnode = entry(punit, node_t, hash);
        if (pnode->a != 6) {
                pw("hash_find");
                return;
        }
	
	punit = (hash_t *)hash_find(&head, 5, 2);
	if (punit != NULL) {
		pw("hash_find");
		return ;
	}
        pr("hash_find");
}

void check_hash_is_exist() {
	hash_head_t head;
        hash_t * punit;
        node_t nodes[N];
        node_t nodes1[N];
        node_t *pnode;
        int i = 0;

        init_head(hash_head_t, &head);
        char * p = (char *) malloc( sizeof(hash_t *) * N);
        hash_set_space(&head, p, sizeof(hash_t *) * N);

        for (i = 0; i < N; i++) {
                nodes[i].a = i+1;
                nodes1[i].a = i+1;
                hash_set_key(&(nodes[i].hash), i);
                hash_set_key(&(nodes1[i].hash), i);
        }
        for (i = 0; i < N; ++i) {
		if (hash_is_exist(&head, &nodes[i].hash)) {
			printf("wrong:hash_is_exist\n");						
			return ;	
		}
                hash_add(&head, &(nodes[i].hash));
		if (!hash_is_exist(&head, &nodes[i].hash)) {
			printf("wrong:hash_is_exist\n");						
			return ;	
		}
		if (hash_is_exist(&head, &nodes1[i].hash)) {
			printf("wrong:hash_is_exist\n");						
			return ;	
		}
                hash_add(&head, &(nodes1[i].hash));
		if (!hash_is_exist(&head, &nodes1[i].hash)) {
			printf("wrong:hash_is_exist\n");						
			return ;	
		}
        }
	printf("right:hash_is_exist\n");
}
int main() {
	check_hash_set_space();	
	check_hash_set_function();	
	check_hash_is_empty();
	check_hash_empty();
	check_hash_set_key();
	check_hash_add();
	check_hash_del();
	check_hash_del_by_key();
	check_hash_find_count();
	check_hash_find();
	check_hash_is_exist();
	return 0;
}
